﻿///IT WAS FUCKING HARD TO PROGRAM SO IT BETTER BE FUCKING HARD TO USE!
///nzbfetch.cs is the heart of this project followed closely by hellanzb.cs
///nzbfetch performs the majority of the tasks and hellanzb.cs monitors HellaNZB
///however, XMLRPC is tempermental and I lack experience so instead of everything hellanzb
///related being in hellanzb.cs, its split between myleech.cs and hellanzb.cs
///I'll change this eventually or, while your here, its a job that needs done ;)
///...whoever you are...
///
///MyLeech MediaPortal Plugin by Vince Mitchell <vince.mhairi@googlemail.com>
using System;
using System.Timers;
using System.Diagnostics;


using MediaPortal.GUI.Library;
using MediaPortal.Dialogs;
using MediaPortal.Util;
using MediaPortal.Profile;


namespace MyLeech
{
  public class MyLeech : GUIWindow, ISetupForm
  {
    #region SkinControlAttribute

    [SkinControlAttribute(2)]
    protected GUIButtonControl btnAutoSearch = null; 
    [SkinControlAttribute(3)]
    protected GUIButtonControl btnBasicSearch = null;
    [SkinControlAttribute(4)]
    protected GUIButtonControl btnJobQueue = null;
    [SkinControlAttribute(5)]
    protected GUIToggleButtonControl btnPause = null;

    [SkinControlAttribute(50)]
    protected GUIListControl lstItems = null;

    #endregion

    #region ISetupForm Members

    // Returns the name of the plugin which is shown in the plugin menu
    public string PluginName()
    {
      return "MyLeech";
    }

    // Returns the description of the plugin is shown in the plugin menu
    public string Description()
    {
      return "Hellanzb interface";
    }

    // Returns the author of the plugin which is shown in the plugin menu
    public string Author()
    {
      return "Vincent Mitchell";
    }

    // Indicates whether plugin can be enabled/disabled
    public bool CanEnable()
    {
      return true;
    }

    // Get Windows-ID
    public int GetWindowId()
    {
      // WindowID of windowplugin belonging to this setup
      // enter your own unique code
      return 3323;
    }

    // Indicates if plugin is enabled by default;
    public bool DefaultEnabled()
    {
      return true;
    }

    // indicates if a plugin has it's own setup screen
    public bool HasSetup()
    {
      return true;
    }
    // show the setup dialog
    public void ShowPlugin()
    {
      frmSetup frmSetupDialog = new frmSetup();
      frmSetupDialog.Show();
    }
    /// <summary>
    /// If the plugin should have it's own button on the main menu of Mediaportal then it
    /// should return true to this method, otherwise if it should not be on home
    /// it should return false
    /// </summary>
    /// <param name="strButtonText">text the button should have</param>
    /// <param name="strButtonImage">image for the button, or empty for default</param>
    /// <param name="strButtonImageFocus">image for the button, or empty for default</param>
    /// <param name="strPictureImage">subpicture for the button or empty for none</param>
    /// <returns>true : plugin needs it's own button on home
    /// false : plugin does not need it's own button on home</returns>

    public bool GetHome(out string strButtonText, out string strButtonImage,
      out string strButtonImageFocus, out string strPictureImage)
    {
      strButtonText=PluginName();
      strButtonImage=String.Empty;
      strButtonImageFocus=String.Empty;
      strPictureImage=String.Empty;
      return true;
    }

    // With GetID it will be an window-plugin / otherwise a process-plugin
    // Enter the id number here again
     public override int GetID
    {
      get
      {
        return 3323;
      }

      set
      {
      }
    }

    #endregion

     #region Definitions
     private mediaportalFunc Dialogs = new mediaportalFunc(); //guiwindows
     private statusTimer Status = new statusTimer(); //status timer
     private DirectoryWatch DIR_WATCH = new DirectoryWatch(); //directory timer
     private JOBQueue JOBQUEUE = new JOBQueue();
     private HELLANZB_FUNC HELLANZB = new HELLANZB_FUNC(); //new instance of client funcs
     private Sites.iSites Site;
     private status STATUS = new status();
     #endregion
     public override bool Init()
    {
      // Load XML Skin
      return Load(GUIGraphicsContext.Skin+@"\MyLeech.xml");
    }
     #region ON_ACTION
     protected override void OnClicked(int controlId, GUIControl control,
      MediaPortal.GUI.Library.Action.ActionType actionType)
    {
      if (control == btnAutoSearch) { this.AutoSearch(lstItems); }
      if (control == btnBasicSearch) { this.BasicSearch(lstItems); }
      if (control == btnPause) { this.HELLANZB.Pause(btnPause.Selected, Status); }
      if (control == btnJobQueue) { this.JobQueue(lstItems); }
      if (control == lstItems)
      {
        switch (lstItems.ListItems[lstItems.SelectedListItemIndex].ItemId)
        {
          case 1: //used for search results.
            this.Download(lstItems.ListItems[lstItems.SelectedListItemIndex]);
            break;
          case 2: //used for JobQueue
            this.Job_Queue_Control(lstItems.ListItems[lstItems.SelectedListItemIndex], lstItems);
            break;
          case 3: //only used for "Processing..." items in JobQueue
            break;
        }
      } base.OnClicked(controlId, control, actionType);
    }
    //################## TIMER FUNCTIONS ############################
    public void OnTimer(object sender, System.Timers.ElapsedEventArgs e)
    {
      this.STATUS = this.HELLANZB.getStatus(Status, btnPause); //get status on timer
    }
    public void OnDirTimer(object sender, System.Timers.ElapsedEventArgs e)
    {
      this.HELLANZB.Watch_Dir(DIR_WATCH); //look in watch directory
    }
    public void OnJobQueue(object sender, System.Timers.ElapsedEventArgs e)
    {
      //update status
      this.JobQueue(lstItems);
    }
    //###############################################################

    //####################### ON PAGE LOAD ##########################
    protected override void OnPageLoad()
    {
      //Check Internet First.
      if (Sites.HTTP_Common.ConnectionExists())
      {
        // Load Settings
        Settings mpSettings = new Settings(MediaPortal.Configuration.Config.GetFolder(MediaPortal.Configuration.Config.Dir.Config) + @"\MyLeech.xml");

        // Setup Page Title
        // ##################################################

        GUIPropertyManager.SetProperty("#PageTitle", "MyLeech"); //Set Default Title
        GUIPropertyManager.SetProperty("#Status", "Waiting on user interaction..."); //default status
        // ##################################################

        // Start Timers
        // ##################################################
        this.Status.KeepAlive = false;
        this.Status.tmrTimer = new Timer();
        this.Status.tmrTimer.Elapsed += new System.Timers.ElapsedEventHandler(OnTimer);
        this.Status.tmrTimer.Interval = ((mpSettings.GetValueAsInt("#Hellanzb", "UpFrequency", 2)) * 1000);
        this.Status.tmrTimer.Enabled = true;
        // ##################################################
        this.JOBQUEUE.tmrTimer = new Timer();
        this.JOBQUEUE.tmrTimer.Elapsed += new System.Timers.ElapsedEventHandler(OnJobQueue);
        this.JOBQUEUE.tmrTimer.Interval = ((mpSettings.GetValueAsInt("#Hellanzb", "UpFrequency", 2)) * 1000);
        this.JOBQUEUE.tmrTimer.Enabled = false;
        if (mpSettings.GetValueAsBool("#Plugin", "move_files", true))
        {
          this.DIR_WATCH.tmrTimer = new Timer();
          this.DIR_WATCH.tmrTimer.Elapsed += new System.Timers.ElapsedEventHandler(OnDirTimer);
          this.DIR_WATCH.tmrTimer.Interval = (20 * 1000); //check the folder every 20 seconds
          this.DIR_WATCH.tmrTimer.Enabled = true;
        }
        this.HELLANZB.getStatus(Status, btnPause); //Get Status to get us started.
        //###################################################
        mpSettings.Dispose(); //Dispose of MediaPortal Settings 
        }
      else
      {
        //Connection doesn't exist. Disable all the buttons
        btnAutoSearch.Disabled = true;
        btnBasicSearch.Disabled = true;
        btnJobQueue.Disabled = true;
        btnPause.Disabled = true;
        GUIPropertyManager.SetProperty("#Status", "No Internet Connection Found");
      }
    }
    protected override void OnPageDestroy(int newWindowId)
    {
      this.Status.KeepAlive = this.Status.tmrTimer.Enabled; //keep our timer
      this.JOBQUEUE.tmrTimer.Enabled = false;
      base.OnPageDestroy(newWindowId);
    }
    #endregion
    //######GUI CONTROL FUNCTIONS INC.GET WEBSITE RESULTS####
    #region GUI_LIST_CONTROLS
    private void BasicSearch(GUIListControl lstItemList)
    {
      JOBQUEUE.tmrTimer.Enabled = false;
      //Set status
      
      GUIPropertyManager.SetProperty("#Status", "Please Select A WebSite To Search...");
      switch (Dialogs.Menu(new string[] { "Binsearch.Info", "NewzLeech", "NZBClub", "NZBIndex" }, "Choose Website..."))
      {
        case "Binsearch.Info":
          Site = new Sites.Binsearch();
          Site.Do_Search(1, lstItemList);
          
          break;
        case "NewzLeech":
          Site = new Sites.NewzLeech();
          Site.Do_Search(1, lstItemList);
          break;
        case "NZBClub":
          break;
        case "NZBIndex":
          break;
      }
      this.LooseFocus(); //switch focus
      lstItemList.Focus = true;
    }
    private void AutoSearch(GUIListControl lstItemList){
      JOBQUEUE.tmrTimer.Enabled = false;
      //Change Status
      GUIPropertyManager.SetProperty("#Status", "Please Select a Search Type...");
      switch (this.Dialogs.Menu(new string[] {"Auto Movie Search"}, "Auto Search Type"))
      {
        case "Auto Movie Search": //Initiate Auto Movie Search
          switch (Dialogs.Menu(new string[] { "Binsearch.Info", "NewzLeech", "NZBClub", "NZBIndex" }, "Choose Website..."))
          {
            case "Binsearch.Info":
              Site = new Sites.Binsearch();
              Site.Do_Search(0, lstItemList);

              break;
            case "NewzLeech":
              Site = new Sites.NewzLeech();
              Site.Do_Search(0, lstItemList);
              break;
            case "NZBClub":
              break;
            case "NZBIndex":
              break;
          }
          break;
        case "Auto TV Series Search": //Yet to be programmed
          this.Dialogs.OK("This is a placeholder for a work in progress feature", "Not Implemented");
          break;
      }
      this.LooseFocus(); //switch focus
      lstItemList.Focus = true;
    }
    private void JobQueue(GUIListControl lstItemList)
    {
      JOBQUEUE.tmrTimer.Enabled = true;
      //load up JobQueue, Refresh status first before doing anything
      lstItemList.Clear();
     
      if (STATUS.currently_processing.Length > 0) //are we processing RAR,PAR files?
      {
        for (int i = 0; i < STATUS.currently_processing.Length; i++)
        { //SHOW PROCESSING ITEMS
          this.Dialogs.AddItem(lstItemList, STATUS.currently_processing[i]["nzbName"].ToString(), "Processing...", STATUS.currently_processing[i]["id"].ToString(), 3);
        }
      }
      if (STATUS.currently_downloading.Length > 0) //are we downloading?
      {
        for (int i = 0; i < STATUS.currently_downloading.Length; i++)
        { //SHOW DOWNLOADING ITEMS
          this.Dialogs.AddItem(lstItemList, STATUS.currently_downloading[i]["nzbName"].ToString(), "Downloading...", STATUS.currently_downloading[i]["id"].ToString(), 2);
        }
      }
      if (STATUS.queued.Length > 0) //do we have a queue
      {
        for (int i = 0; i < STATUS.queued.Length; i++)
        { //SHOW QUEUED ITEMS
          this.Dialogs.AddItem(lstItemList, STATUS.queued[i]["nzbName"].ToString(), "Queued", STATUS.queued[i]["id"].ToString(), 2);
        }
      }
      //this.LooseFocus(); 
      //lstItemList.Focus = true; //CHANGE QUEUELIST TO CURRENT FOCUS
      GUIPropertyManager.SetProperty("#PageTitle", "MyLeech - Job Queue");//CHANGE PAGETITLE
      GUIPropertyManager.SetProperty("#Status", STATUS.currently_downloading.Length.ToString() + " NZBs Downloading and " + STATUS.queued.Length + " Queued");
      return;


    }
    #endregion
    //###############################################
    //############ DO Functions. ####################
    #region MyLeech Window to Core Functions
    private void Download(GUIListItem lstItem)
    {
      Sites.HTTP_Common HTTP_Common = new Sites.HTTP_Common();
      if(Dialogs.YesNo("Are You Sure You Want To Download "+lstItem.Label,"NZB Download")){
        //They want us to download an NZB? How ubsurd! we can't do that! ...
        //we can! Watch, its magic.
        string POSTDATA = String.Empty;
        switch (Site.SiteName)
        {
          case "Binsearch":
            POSTDATA = "action=nzb&"+lstItem.Path+"=on";
            break;
          case "NewzLeech":
            string HTML = HTTP_Common.Fetch_HTML("http://www.newzleech.com/index.php?p="+lstItem.Path,Site.REFERER).Replace(" ", "");
            if (HTML.Length < 100) { Dialogs.OK("Unable to retrieve HTML from NewzLeech", "Error"); return; }
            string matchPattern = @"""binary\[\]""\s?\s?value=""(?<ID>[1-9].*?)""";
            string binary = String.Empty;
            foreach (System.Collections.Hashtable grouping in
               HTTP_Common.ExtractGroupings(HTML, matchPattern, true))
            {
              foreach (System.Collections.DictionaryEntry DE in grouping)
              {
                if ((DE.Key.ToString()) != "0")
                {
                  string Value = System.Web.HttpUtility.HtmlDecode(DE.Value.ToString().Trim());
                  string Key = DE.Key.ToString();
                  binary = binary + "&binary[]=" + (Value.Trim());
                }
              }
            }
            if (binary.Length < 9) { Dialogs.OK("Unable to retrieve NZB from NewzLeech", "Error"); return; }
             
              POSTDATA = "group=&age=&q=&type=&mode=usenet&get=0&offset=0&p="+lstItem.Path+"&getnzb=Get+NZB" + binary.Trim();
              break;
            
        }
        if (HTTP_Common.FETCH_NZB(Site.NZB_Address,Site.REFERER,Site.NZB_Method,POSTDATA,Site.Keyword))
        {
          this.Dialogs.OK(lstItem.Label + " Added To Queue", "Item Added To Queue");
          return;
        }
        else
        {
          this.Dialogs.OK("Failed To Download NZB", "Error");
          return;
        }
      }
      
          
      
    }
    private void Job_Queue_Control(GUIListItem lstItem,GUIListControl lstItemControl)
    {
      JOBQUEUE.tmrTimer.Enabled = false;
      //Show a MENU with the options for Downloadin nzb: Cancel
      //Show a MENU with the options for queued item: Force Download Now, Move Up, Move Down, Cancel
      switch (lstItem.Label2)
      {
        case "Downloading...": //its an item that is downloading
          switch (this.Dialogs.Menu(new string[] { "Cancel"}, "Download Options"))
          {
            case "Cancel":
              this.HELLANZB.SEND_OPTION("-1", "Cancel", this.Status); //Send Cancel Command
              break;
          }
          break;
        case "Queued":
          switch (this.Dialogs.Menu(new string[] { "Force Download Now", "Move Up", "Move Down", "Move To Top", "Move To Bottom", "Cancel" }, "Queued Options"))
          {
            case "Force Download Now":
              this.HELLANZB.SEND_OPTION(lstItem.Path, "Force", this.Status); //Send Force Command
              break;
            case "Move Up":
              this.HELLANZB.SEND_OPTION(lstItem.Path, "Move_Up", this.Status); //Send Move_Up Command
              break;
            case "Move Down":
              this.HELLANZB.SEND_OPTION(lstItem.Path, "Move_Down", this.Status); //Send Move Down Command
              break;
            case "Move To Top":
              this.HELLANZB.SEND_OPTION(lstItem.Path, "Move_Next", this.Status); //Send Move Next Command
              break;
            case "Move To Bottom":
              this.HELLANZB.SEND_OPTION(lstItem.Path, "Move_Last", this.Status); //Send Move Last Command
              break;
            case "Cancel":
              this.HELLANZB.SEND_OPTION(lstItem.Path, "Dequeue", this.Status); //Send Dequeue Command
              break;
          }
          break;

      }
      this.HELLANZB.getStatus(this.Status, btnPause);
      this.JobQueue(lstItemControl); //Update Job Queue
    }   
    #endregion
    //###############################################
  }
}